package net.csdn.business.kanban.api.facade;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.date.DateUtil;
import com.alibaba.fastjson2.JSON;
import com.alibaba.fastjson2.JSONArray;
import com.alibaba.fastjson2.JSONObject;
import lombok.RequiredArgsConstructor;
import net.csdn.business.kanban.api.entity.KanbanDetail;
import net.csdn.business.kanban.api.enums.BusinessTypeEnums;
import net.csdn.business.kanban.api.enums.SystemFieldEnums;
import net.csdn.business.kanban.api.service.KanbanDetailService;
import net.csdn.business.kanban.api.service.KanbanFieldService;
import net.csdn.business.kanban.api.service.KanbanService;
import net.csdn.business.kanban.common.constant.RedisConstants;
import net.csdn.business.kanban.common.domain.DTO.*;
import net.csdn.business.kanban.common.domain.request.IssueLinkKanbanUpdateParam;
import net.csdn.business.kanban.common.domain.request.KanbanDetailAddParam;
import net.csdn.business.kanban.common.domain.request.KanbanDetailUpdateParam;
import net.csdn.business.kanban.common.domain.request.MoveIssueParam;
import net.csdn.business.kanban.common.domain.resp.IssueInfoResp;
import net.csdn.business.kanban.common.domain.resp.KanbanDetailResp;
import net.csdn.business.kanban.common.domain.resp.KanbanFieldResp;
import net.csdn.business.kanban.common.enums.ActionSyncKanban;
import net.csdn.business.kanban.common.enums.ResultCodeEnum;
import net.csdn.business.kanban.common.service.CommonAsyncService;
import net.csdn.business.kanban.common.utils.ExceptionUtil;
import net.csdn.business.kanban.common.utils.ObjectId;
import net.csdn.business.kanban.feign.api.IssueFeignClient;
import net.csdn.business.kanban.feign.api.ProjectFeignClient;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.stereotype.Service;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.RequestBody;

import java.util.*;
import java.util.stream.Collectors;

/**
 * @ClassName kanbanDetailFacade
 * @Description TODO
 * @Author liuzhisheng
 * @Date 2023/9/19
 **/
@Service
@RequiredArgsConstructor
public class KanbanDetailFacade {
    @Value("${kanban.detail.row.limit}")
    private Long limitNum;

    @Value("${atomgit.domain:https://test.test.com}")
    private String domain;

    private final KanbanDetailService kanbanDetailService;
    private final IssueFeignClient issueFeignClient;
    private final KanbanFieldFacade kanbanFieldFacade;
    private final ProjectFeignClient projectFeignClient;
    private final KanbanFieldService kanbanFieldService;
    private final CommonAsyncService commonAsyncService;

    /**
     * 获取详情
     * @param objectId
     * @param uid
     * @return
     */
    public IssueInfoResp getKanbanDetailById(String objectId,String uid){
        IssueInfoResp issueInfoResp = new IssueInfoResp();
        KanbanDetail kanbanDetail = kanbanDetailService.getKanbanDetailByObjectId(objectId);
        if(kanbanDetail == null){
            ExceptionUtil.throwBizException(ResultCodeEnum.KANBAN_NOT_EXSIT);
        }
        IssueVoDto issueVoDto = issueFeignClient.issueDetail(kanbanDetail.getBusinessId(),uid);
//        if(issueVoDto.getAuditStatus() < AuditStatusEnum.INIT.getCode()){
//            ExceptionUtil.throwBizException(ResultCodeEnum.RESOURCE_NOT_EXIST);
//        }
        issueInfoResp.setIssueVoDto(issueVoDto);
        issueInfoResp.setFieldContentJson(JSON.parseObject(kanbanDetail.getFieldContentJson()));

        /**获取所有字段*/
        List<KanbanFieldResp> kanbanFieldResps = kanbanFieldFacade.fieldSettings(kanbanDetail.getKanbanId());
        issueInfoResp.setFieldRespList(kanbanFieldResps);
        return issueInfoResp;
    }

    /**
     * 获取issue url
     * @param objectId
     * @return
     */
    @Cacheable(value = RedisConstants.KANBAN, key = "'issue-url-' + #objectId", unless = "null == #result")
    public String getIssueUrl(String objectId){
        KanbanDetail kanbanDetail = kanbanDetailService.getKanbanDetailByObjectId(objectId);
        if(kanbanDetail == null){
            ExceptionUtil.throwBizException(ResultCodeEnum.KANBAN_NOT_EXSIT);
        }
        ProjectVo projectVo = projectFeignClient.getProjectById(kanbanDetail.getProjectId());
        StringBuilder profileUrl=new StringBuilder(domain);
        profileUrl.append("/").append(projectVo.getPathWithNamespace()).append("/issues/").append(kanbanDetail.getSerialNumber());
        return profileUrl.toString();
    }

    /**
     * 内容编辑
     * @param param
     * @return
     */
    public boolean updateKanbanDetail(KanbanDetailUpdateParam param){
        KanbanDetail kanbanDetail = kanbanDetailService.getKanbanDetailByObjectId(param.getObjectId());
        if(kanbanDetail == null){
            ExceptionUtil.throwBizException(ResultCodeEnum.KANBAN_NOT_EXSIT);
        }
        /**是否有更新*/
        boolean flag = false;
        if(SystemFieldEnums.TITLE.getName().equals(param.getFieldId())){
            if(!Objects.equals(kanbanDetail.getTitle(),param.getFieldValue())){
                kanbanDetailService.updateTitle(kanbanDetail.getId(),param.getFieldValue());

                commonAsyncService.requestAsync(() -> this.linkIssueUpdate(SystemFieldEnums.TITLE,param.getCurrUserId(),
                        kanbanDetail.getProjectId(),kanbanDetail.getBusinessId(),param.getFieldValue(),kanbanDetail.getTitle()));
            }
        }else if(SystemFieldEnums.ASSIGNEE.getName().equals(param.getFieldId())){
            if(!Objects.equals(kanbanDetail.getAssignee(),param.getFieldValue())){
                kanbanDetailService.updateAssignee(kanbanDetail.getId(),param.getFieldValue());

                commonAsyncService.requestAsync(() -> this.linkIssueUpdate(SystemFieldEnums.ASSIGNEE,param.getCurrUserId(),
                        kanbanDetail.getProjectId(),kanbanDetail.getBusinessId(),param.getFieldValue(),kanbanDetail.getAssignee()));
            }
        }else if(SystemFieldEnums.LABELS.getName().equals(param.getFieldId())){
            if(!Objects.equals(kanbanDetail.getLabels(),param.getFieldValue())){
                try {
                    JSON.parseArray(param.getFieldValue(),String.class);
                } catch (Exception e) {
                    ExceptionUtil.throwBizException(ResultCodeEnum.KANBAN_INCORRECT_FORMAT);
                }
                kanbanDetailService.updateLabels(kanbanDetail.getId(),param.getFieldValue());

                commonAsyncService.requestAsync(() -> this.linkIssueUpdate(SystemFieldEnums.LABELS,param.getCurrUserId(),
                        kanbanDetail.getProjectId(),kanbanDetail.getBusinessId(),param.getFieldValue(),kanbanDetail.getLabels()));
            }
        }else if(SystemFieldEnums.MILESTONE.getName().equals(param.getFieldId())){
            if(!Objects.equals(kanbanDetail.getMilepost(),param.getFieldValue())){
                kanbanDetailService.updateMilepost(kanbanDetail.getId(),param.getFieldValue());

                commonAsyncService.requestAsync(() -> this.linkIssueUpdate(SystemFieldEnums.MILESTONE,param.getCurrUserId(),
                        kanbanDetail.getProjectId(),kanbanDetail.getBusinessId(),param.getFieldValue(),kanbanDetail.getMilepost()));
            }
        }else {
            /**判断更新的字段是否存在*/
            Boolean isExistField = kanbanFieldService.isExistField(kanbanDetail.getKanbanId(),param.getFieldId());
            if(!isExistField){
                ExceptionUtil.throwBizException(ResultCodeEnum.KANBAN_NOT_EXSIT,"字段资源不存在");
            }
            JSONObject jsonObject = JSON.parseObject(kanbanDetail.getFieldContentJson());
            jsonObject = jsonObject == null ? new JSONObject() : jsonObject;
            if(!Objects.equals(jsonObject.getString(param.getFieldId()),param.getFieldValue())){
                if(StringUtils.isNotBlank(param.getFieldValue())){
                    jsonObject.put(param.getFieldId(),param.getFieldValue());
                }else {
                    jsonObject.remove(param.getFieldId());
                }
                kanbanDetailService.updateFieldContentJson(kanbanDetail.getId(),jsonObject.toJSONString());
            }
        }
        return true;
    }

    /**
     * 同步更新issue
     * @param systemFieldEnums
     * @param uid
     * @param projectId
     * @param issueId
     */
    public Boolean linkIssueUpdate(SystemFieldEnums systemFieldEnums,String uid,Long projectId,String issueId,String newValue,String oldValue){
        if(SystemFieldEnums.TITLE.getName().equals(systemFieldEnums.getName())){
            /**标题更新*/
            IssueUpdateReqDto issueUpdateReqDto = new IssueUpdateReqDto();
            issueUpdateReqDto.setIssueId(issueId);
            issueUpdateReqDto.setTitle(newValue);
            issueUpdateReqDto.setUid(uid);
            issueUpdateReqDto.setIsSyncKanban(false);
            issueFeignClient.updateIssueTitle(issueUpdateReqDto);
        }else if(SystemFieldEnums.ASSIGNEE.getName().equals(systemFieldEnums.getName())){
            /**设置负责人*/
            IssueAssignUserRequestDto dto = new IssueAssignUserRequestDto();
            dto.setAssignUser(newValue == null ? "" : newValue);
            dto.setIssueId(issueId);
            dto.setUid(uid);
            dto.setIsSyncKanban(false);
            issueFeignClient.updateAssignUser(dto);
        }else if(SystemFieldEnums.LABELS.getName().equals(systemFieldEnums.getName())){
            /**分别计算出那些是需要关联的，那些是需要移除关联的*/
            List<String> old =  JSON.parseArray(oldValue,String.class);
            List<String> newlabels =  JSON.parseArray(newValue,String.class);

            List<String> addLabels = new ArrayList<>();
            List<String> removeLabels = new ArrayList<>();
            if(old == null && newlabels != null){
                addLabels.addAll(newlabels);
            }else if(old != null && newlabels == null){
                removeLabels.addAll(old);
            }else {
                List<String> s1 = old.stream().filter(ss1 -> !newlabels.contains(ss1)).collect(Collectors.toList());
                removeLabels.addAll(s1);
                List<String> s2 =  newlabels.stream().filter(ss2 -> !old.contains(ss2)).collect(Collectors.toList());
                addLabels.addAll(s2);
            }
            if(addLabels.size()>0){
                LabelIssueBatchLinkDto linkDto = new LabelIssueBatchLinkDto();
                linkDto.setCurrUserId(uid);
                List<String> issues = new ArrayList<>();
                issues.add(issueId);
                linkDto.setIssueIds(issues);
                linkDto.setLabelIds(addLabels);
                linkDto.setProjectId(projectId);
                issueFeignClient.batchLinkIssueLabels(linkDto);
            }
            if(removeLabels.size()>0){
                for (String removeLabel : removeLabels) {
                    issueFeignClient.removeIssueLabel(uid,issueId,removeLabel,false);
                }
            }
        }else if(SystemFieldEnums.MILESTONE.getName().equals(systemFieldEnums.getName())){
            MilepostIssueBatchLinkDto dto = new MilepostIssueBatchLinkDto();
            dto.setCrrUserId(uid);
            List<String> issues = new ArrayList<>();
            issues.add(issueId);
            dto.setIssueIds(issues);
            dto.setProjectId(projectId);
            dto.setGoalId(newValue);
            dto.setIsSyncKanban(false);
            if(StringUtils.isEmpty(newValue) && StringUtils.isNotEmpty(oldValue)){
                dto.setGoalId(oldValue);
                issueFeignClient.batchRemoveIssueeMilepost(dto);
            }else {
                issueFeignClient.batchLinkIssueMilepost(dto);
            }
        }
        return true;
    }
    /**
     * 添加任务
     * @param param
     * @return
     * @throws Exception
     */
    public boolean addKanbanDetail(@RequestBody KanbanDetailAddParam param){
        if(CollectionUtil.isEmpty(param.getIssues())){
            ExceptionUtil.throwBizException(ResultCodeEnum.KANBAN_TASK_NOT_NULL);
        }
        /**判断任务条数是否超出限制*/
        long countRow = kanbanDetailService.countRow(param.getKanbanId());
        if(countRow+param.getIssues().size() > limitNum){
            ExceptionUtil.throwBizException(ResultCodeEnum.KANBAN_LIMIT_TASKROW);
        }

        /**判断当前看板中是否存在issueId*/
        boolean isExist = kanbanDetailService.isBatchExist(param.getKanbanId(),param.getIssues());
        if(isExist){
            ExceptionUtil.throwBizException(ResultCodeEnum.KANBAN_TASK_EXSIT);
        }

        /**批量获取issue*/
        List<IssueVoDto> issueVoDtos = issueFeignClient.batchGetIssueSimple(param.getIssues());
        ArrayList<KanbanDetail> details = new ArrayList<>();
        issueVoDtos.stream().forEach(bean -> {
            KanbanDetail kanbanDetail = new KanbanDetail();
            kanbanDetail.setObjectId(ObjectId.get().toString());
            kanbanDetail.setKanbanId(param.getKanbanId());
            kanbanDetail.setProjectId(bean.getProjectId());
            kanbanDetail.setBusinessType(BusinessTypeEnums.ISSUE.getCode());
            kanbanDetail.setBusinessId(bean.getIssueId());
            kanbanDetail.setBusinessStatus(bean.getStatus());
            kanbanDetail.setArchivedTask(false);
            kanbanDetail.setTitle(bean.getTitle());
            kanbanDetail.setAssignee(bean.getAssignUser());
            if(CollectionUtil.isNotEmpty(bean.getLabels())){
                List<String> labels = bean.getLabels().stream().map(LabelVo::getObjectId).collect(Collectors.toList());
                kanbanDetail.setLabels(JSON.toJSONString(labels));
            }
            kanbanDetail.setMilepost(bean.getMilepostId());
            kanbanDetail.setCreatorId(param.getCurrUserId());
            kanbanDetail.setSerialNumber(bean.getSerialNumber());
            details.add(kanbanDetail);
        });
        return kanbanDetailService.saveBatch(details);
    }

    /**
     * 看板明细列表
     * @return
     */
    public List<KanbanDetailResp> kanbanDetailsList(String kanbanId,Boolean archivedTask){
        List<KanbanDetail> kanbanDetailList = kanbanDetailService.kanbanDetailsList(kanbanId,limitNum,archivedTask);
        if(CollectionUtil.isEmpty(kanbanDetailList)){
            return new ArrayList<>();
        }
        List<KanbanDetailResp> resps = BeanUtil.copyToList(kanbanDetailList,KanbanDetailResp.class);
        List<Long> projectIds= resps.stream().map(KanbanDetailResp::getProjectId).distinct().collect(Collectors.toList());
        List<ProjectVo> ProjectVoList = new ArrayList<>();
        projectIds.forEach(repoId ->{
            ProjectVo projectVo = projectFeignClient.getProjectById(repoId);
            ProjectVoList.add(projectVo);
        });

        /**获取所有的labelID*/
        List<String> labelIds = new ArrayList<>();
        resps.stream().forEach(bean -> {
            if(StringUtils.isNotBlank(bean.getLabels())){
                List<String> ss = JSON.parseArray(bean.getLabels(),String.class);
                labelIds.addAll(ss);
            }
        });
        if(labelIds.size()>0){
            /**去重*/
            List<String>  labels = labelIds.stream().distinct().collect(Collectors.toList());
            Map<String, LabelVo> labelVoMap = issueFeignClient.getBatchLabels(labels);
            resps.stream().forEach(bean -> {
                List<LabelVo> labelVoList = new ArrayList<>();
                if(StringUtils.isNotBlank(bean.getLabels())){
                    JSONArray array = JSON.parseArray(bean.getLabels());
                    array.forEach(s -> {
                        labelVoList.add(labelVoMap.get(s));
                    });
                }
                bean.setLabelVos(labelVoList);
            });
        }
        /**设置负责人*/
        List<String> uids = resps.stream().map(KanbanDetailResp::getAssignee).distinct().filter(uid1 -> StringUtils.isNotBlank(uid1)).collect(Collectors.toList());
        if(uids.size()>0){
            Map<String, UserVo> userVoMap = issueFeignClient.getBatchAssignUsers(uids);
            resps.stream().forEach(bean -> {
                if(StringUtils.isNotBlank(bean.getAssignee())){
                    bean.setAssignUserInfo(userVoMap.get(bean.getAssignee()));
                }
            });
        }
        /**设置里程碑*/
        List<String> mileposts = resps.stream().map(KanbanDetailResp::getMilepost).distinct().collect(Collectors.toList());
        if(mileposts.size()>0){
            Map<String, MilepostVo> milepostVoMap = issueFeignClient.getBatchMileposts(mileposts);
            resps.stream().forEach(bean -> {
                if(StringUtils.isNotBlank(bean.getMilepost())){
                    bean.setMilepostObj(milepostVoMap.get(bean.getMilepost()));
                }
            });
        }
        /**组装*/
        resps.stream().forEach(bean -> {
            JSONObject jsonObject = new JSONObject();
            if(bean.getFieldContentJson() != null){
                jsonObject =  JSON.parseObject(bean.getFieldContentJson());
            }
            jsonObject.put(SystemFieldEnums.TITLE.getName(),bean.getTitle());
            jsonObject.put(SystemFieldEnums.ASSIGNEE.getName(),bean.getAssignUserInfo());
            jsonObject.put(SystemFieldEnums.LABELS.getName(),bean.getLabelVos());
            jsonObject.put(SystemFieldEnums.MILESTONE.getName(),bean.getMilepostObj());
            bean.setFieldContentJsonObj(jsonObject);


            /**设置项目名称*/
            Optional<ProjectVo> optional = ProjectVoList.stream().filter(vo -> vo.getId().equals(bean.getProjectId())).findFirst();
            if(optional.isPresent()){
                bean.setProjectName(optional.get().getName());
            }
        });
        return resps;
    }


    /**
     * issue关联更新看板内容
     * @param param
     * @return
     */
    public void issueLinkUpdate(IssueLinkKanbanUpdateParam param){
        List<KanbanDetail> kanbanDetails = kanbanDetailService.getKanbanDetail(param.getBusinessType(),param.getBusinessIds());
        if(CollectionUtil.isEmpty(kanbanDetails)){
            return;
        }
        kanbanDetails.stream().forEach(kanbanDetail -> {
            if(SystemFieldEnums.TITLE.getName().equals(param.getFieldId())){
                if(!Objects.equals(kanbanDetail.getTitle(),param.getFieldValue())){
                    kanbanDetailService.updateTitle(kanbanDetail.getId(),param.getFieldValue());
                }
            }else if(SystemFieldEnums.ASSIGNEE.getName().equals(param.getFieldId())){
                if(!Objects.equals(kanbanDetail.getAssignee(),param.getFieldValue())){
                    kanbanDetailService.updateAssignee(kanbanDetail.getId(),param.getFieldValue());
                }
            }else if(SystemFieldEnums.LABELS.getName().equals(param.getFieldId())){
                List<String> labes = JSON.parseArray(kanbanDetail.getLabels(),String.class);
                if(ActionSyncKanban.UPDATE.equals(param.getAction())){
                    if(CollectionUtil.isEmpty(labes)){
                        labes = new ArrayList<>();
                        labes.add(param.getFieldValue());
                    }else {
                        labes.add(param.getFieldValue());
                    }
                }else {
                    if(CollectionUtil.isNotEmpty(labes) && labes.contains(param.getFieldValue())){
                        labes.remove(param.getFieldValue());
                    }
                }
                kanbanDetailService.updateLabels(kanbanDetail.getId(),JSON.toJSONString(labes));
            }else if(SystemFieldEnums.MILESTONE.getName().equals(param.getFieldId())){
                if(!Objects.equals(kanbanDetail.getMilepost(),param.getFieldValue())){
                    kanbanDetailService.updateMilepost(kanbanDetail.getId(),param.getFieldValue());
                }
            }
        });
    }

    /**
     * @Desc: 刪除issueId相关的所有看板内容
     * @author: liuzhisheng
     * @date: 2023/11/15 14:11
     */
    public void removeIssue(String issueId){
        kanbanDetailService.removeIssue(issueId);
    }

    /**
     * @Desc: 转移issue时，同步更新看板issue
     * @author: liuzhisheng
     * @date: 2023/11/15 16:45
     */
    public void moveIssue(MoveIssueParam param){
        /**根据issueId获取看板中的所有相关内容*/
        List<KanbanDetail> detailList = kanbanDetailService.queryIssueDetailList(param.getOldIssueId());
        if(CollectionUtil.isNotEmpty(detailList)){
            List<Long> ids = detailList.stream().map(KanbanDetail::getId).collect(Collectors.toList());
            kanbanDetailService.batchUpdateIssueDetail(ids,param);
        }
    }
}
